/*
 * Copyright (C) 2008 Peter Kling
 *
 * This file is part of 'A Kind of Billiard', a graphical billiard simulation.
 *
 * 'A Kind of Billiard' is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * 'A Kind of Billiard' is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * 'A Kind of Billiard'. If not, see <http://www.gnu.org/licenses/>.
 */

package cg2.mathematics;

/**
 * @brief An euclidean vector supporting vector addition, scalar multiplication and computation of the norm.
 */
public class MathVector implements Cloneable {
	private final double[] data;
	public  final int dim;
	
	/**
	 * @brief Creates an i-dimensional vector.
	 */
	public MathVector(int i) {
		data = new double[i];
		dim = i;
	}
	
	/**
	 * @brief Adds the given vector to this vector.
	 * @throws IllegalArgumentException if the dimensions of the vectors do not match. 
	 */
	public void add(MathVector v) {
		if (dim != v.dim)
			throw new IllegalArgumentException("Dimensions of vectors do not match.");
		for (int i=0; i<dim; i++)
			data[i] += v.get(i);
	}
	
	/**
	 * @brief Returns a copy of this vector.
	 */
	@Override
	public MathVector clone() {
		MathVector v = new MathVector(dim);
		v.add(this);
		return v;
	}
	
	/**
	 * @brief Returns the requested component of this vector.
	 */
	public double get(int i) {
		return data[i];
	}
	
	/**
	 * @brief Multiplies this vector with a scalar.
	 */
	public void mul(double s) {
		for (int i=0; i<dim; i++)
			data[i] *= s;
	}
	
	/**
	 * @brief Returns the norm of this vector.
	 */
	public double norm() {
		return Math.sqrt(Mathematics.mul(this, this));
	}
	
	/**
	 * @brief Normalizes this vector.
	 */
	public void normalize() {
		double vectorNorm = norm();
		for (int i=0; i<dim; i++)
			data[i] /= vectorNorm;
	}
	
	/**
	 * @brief Sets the given vector component to the given value.
	 */
	public void set(int i, double value) {
		data[i] = value;
	}
	
	/**
	 * @brief Subtracts the given vector from this one.
	 * @throws IllegalArgumentException if the dimensions of the vectors do not match.
	 * @return This vector.
	 */
	public void sub(MathVector v) {
		if (dim != v.dim)
			throw new IllegalArgumentException("Dimensions of vectors do not match.");
		for (int i=0; i<dim; i++)
			data[i] -= v.get(i);
	}
	
	/**
	 * @brief Returns an array representing this vector.
	 */
	public double[] toArray(){
		double[] result = new double[dim];
		for (int i = 0; i < dim; i++)
			result[i] = data[i];
		return result;
	}
	
	/**
	 * @brief Returns a readable representation of this vector.
	 */
	public String toString() {
		String str = "[";
		for (int i=0; i<data.length-1; i++)
			str += data[i] + ", ";
		str += data[data.length-1] + "]";
		return str;
	}
}
